【新機能】Amazon API Gatewayを使ってAWS LambdaをSDKなしでHTTPS越しに操作する
こんにちは、せーのです。今日はLambdaがより使いやすくなる新機能をご紹介します。 サラッと今朝出たての新しいサービスが登場したりしますが、社内のチャットがざわざわしていたのでその詳しい解説はまた別の記事で紹介されるかと思います。 今回の新機能はLambda FunctionをAPI化してしまってSDKのインクルードなしに叩いてしまおう、という機能です。
LambdaをWebから叩くにはSDKが必要
先日、こんな記事を書きました。
Amazon EC2を(なるべく)使わずにシステムを構築してみる
この記事の中でLambdaをJavaScriptから直接叩いたことに意外と反響がありました。Lambdaで動くようなマイクロな関数であればもはやEC2は要らないんですね。 ただこのようにWebからJavaScriptを使ってLambdaを叩くにはこの記事にあるように「AWS SDKのセット」と「関連サービスのインクルード」「Cognitoの設定」が必要です。AWS SDKに関してはカスタマイズして必要なサービスのみライブラリ化して使うと軽くなっていいかもしれないですね。ただ確かに簡単な関数を叩くだけにしては準備が多く、あまりスマートではないです。
Amazon API Gateway
そこで登場するのができたてほやほやのサービス、「Amazon API Gateway」です。これは簡単に言うとAmazonのクラウド(には限らないのですが)のサービスをAPI化して公開する、というサービスです。これを使うと作成したLambda FunctionがREST API化され、SDKなしに叩くことができるようになります。
やってみた
では早速やってみましょう。マネージメントコンソールからLambdaを開くと、、、おや、外観が随分変わっていますね。
blueprintから選ぶ
これもLambdaの新しい機能(ではないかもしれない)「blueprint」です。blueprint、要するに「青写真」ですね。よく使われるようなユースケースに対して既にサンプルコードを用意しているわけです。 せっかくなので使ってみましょう。blueprintから[microservice-http-endpoint]を選択します。
そうするとおなじみの画面が出てきました。名前をつけて、サンプルコードの中身を見てみましょう。
console.log('Loading function'); var doc = require('dynamodb-doc'); var dynamo = new doc.DynamoDB(); exports.handler = function(event, context) { //console.log('Received event:', JSON.stringify(event, null, 2)); var operation = event.operation; delete event.operation; switch (operation) { case 'create': dynamo.putItem(event, context.done); break; case 'read': dynamo.getItem(event, context.done); break; case 'update': dynamo.updateItem(event, context.done); break; case 'delete': dynamo.deleteItem(event, context.done); break; case 'list': dynamo.scan(event, context.done); break; case 'echo': context.succeed(event); break; case 'ping': context.succeed('pong'); break; default: context.fail(new Error('Unrecognized operation "' + operation + '"')); } };
DynamoDBに対してItemのPut、Get、Update等の基本的な操作を[operation]という引数で制御するサンプルですね。 ではこれを動かしてみましょう。Roleを設定します。今回は[Basic with DynamoDB]を選択します。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "Stmt1428341300017", "Action": [ "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:PutItem", "dynamodb:Query", "dynamodb:Scan", "dynamodb:UpdateItem" ], "Effect": "Allow", "Resource": "*" }, { "Sid": "", "Resource": "*", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Effect": "Allow" } ] }
DynamoDBに関する操作権限とCloudWatch Logsへの書き込み権限が入ってますね。こちらを許可します。 [Next]をクリックするとendpointの設定画面に移ります。
endpointの設定
ここでREST APIに関する設定を行います。
- API name : API名
- Resource name: 対象リソース名。ここを変更すると作成したLambdaにはつながりません。
- Method: メソッド。今回はPOSTメソッドを使います。
- Deployment stage: この関数がどの段階のデプロイなのかを名前をつけて管理します。今回は[prod]のままでいきます。
- Security: APIのセキュリティレベルを決めます。[AWS IAM]はIAMを使って、[Open]は全公開、[Open with access key]はAPI Gatewayを使ってaccess Keyにてセキュリティを管理します。今回は[Open with access key]を使用します。
各種設定が終わったら[Next]をクリックします。確認画面が出るので確認し[Create Function]で作成します。
ローカルテスト
作成したLambda functionをテストしてみましょう。先程作ったFunction名を選び[Code]タブを選択します。
このコードをテストします。左上の[Test]ボタンをクリックします。
サンプルイベントの入力画面が出てきました。今回作成したLambda Functionには「echo」という応答確認用のメソッドがありますのでそちらを使いましょう。こんな感じで入力します。
{ "operation": "echo", "somekey1": "somevalue1", "somekey2": "somevalue2" }
テストしてみると
エラーもなく通っているようです。[echo]の部分のソースは
case 'echo': context.succeed(event); break;
と、ただ入力内容を表示するだけなので特に何かの処理が走るわけでもないようです。
APIのテスト
さて、APIはこれで完成しているのでしょうか。[API endpoints]を見てみます。
endpoint URLがありますね。使えそうです。[POST]リンクをクリックします。
API Gatewayの対象APIの画面に飛びます。作成したLambda Functionまでどのような経路を通ってリクエストが送られるのかが図になってますね。これはわかりやすい! Clientの上に[TEST]というリンクがありますのでこちらでリクエストをテストしてみましょう。
[Request Body]に先程と同じJSONを入力します。
[Test]ボタンをクリックすると擬似的にリクエストがAPI経由でLambdaに飛んでいきます。
無事200が返ってきてますね!ログを詳しく見てみます。
Execution log for request test-request Thu Jul 09 22:03:06 UTC 2015 : Starting execution for request: test-request Thu Jul 09 22:03:06 UTC 2015 : Method request path: {} Thu Jul 09 22:03:06 UTC 2015 : Method request query string: {} Thu Jul 09 22:03:06 UTC 2015 : Method request headers: {} Thu Jul 09 22:03:06 UTC 2015 : Method request body before transformations: { "operation": "echo", "somekey1": "somevalue1", "somekey2": "somevalue2" } Thu Jul 09 22:03:06 UTC 2015 : Endpoint request URI: https://lambda.us-east-1.amazonaws.com/2015-03-31/functions/arn:aws:lambda:us-east-1:887464593869:function:testchao2sukelambda/invocations Thu Jul 09 22:03:06 UTC 2015 : Endpoint request headers: {Authorization=AWS4-HMAC-SHA256 Credential=AKIAJTWD3UHYBH2VLLRA/20150709/us-east-1/lambda/aws4_request, SignedHeaders=accept;content-type;host;x-amz-content-sha256;x-amz-date;x-amz-source-arn, Signature=7f08830b00ba8fe7b127a437f4674e0668289ac420ae16c0e2ee22fbd69b9e30, X-Amz-Date=20150709T220306Z, X-Amz-Source-Arn=arn:aws:execute-api:us-east-1:887464593869:hl3xqc3yrj/null/POST/testchao2sukelambda, Accept=application/json, Host=lambda.us-east-1.amazonaws.com, X-Amz-Content-Sha256=4e3a6c127554027c1ea95cc58b6aaf1d82476c3777fea245f7e525f99b14dedc, Content-Type=application/json} Thu Jul 09 22:03:06 UTC 2015 : Endpoint request body after transformations: { "operation": "echo", "somekey1": "somevalue1", "somekey2": "somevalue2" } Thu Jul 09 22:03:06 UTC 2015 : Endpoint response body before transformations: {"somekey1":"somevalue1","somekey2":"somevalue2"} Thu Jul 09 22:03:06 UTC 2015 : Endpoint response headers: {x-amzn-Remapped-Content-Length=0, x-amzn-RequestId=4729e860-2686-11e5-80f4-d70dbc6f6057, Connection=keep-alive, Content-Length=49, Date=Thu, 09 Jul 2015 22:03:05 GMT, Content-Type=application/json} Thu Jul 09 22:03:06 UTC 2015 : Method response body after transformations: {"somekey1":"somevalue1","somekey2":"somevalue2"} Thu Jul 09 22:03:06 UTC 2015 : Method response headers: {Content-Type=application/json} Thu Jul 09 22:03:06 UTC 2015 : Successfully completed execution
[echo]のoperationは入ったイベントをただ表示するだけなのでresponse bodyにはrequest bodyと同じ値が入っています。 あとはブラウザから先程表示されたエンドポイントに対してリクエストを投げるだけです。これでAPIの完成です。
まとめ
いかがでしたでしょうか。すごく簡単ですね!URLアクセスでLambdaが叩ける、ということはS3にhtmlファイルとJavaScriptを置いて、LambdaとHTTPSでデータのやり取りをすればいいわけで、送ったデータはLambdaからDynamoDBに入れておけば永続化もできますね。つまりいよいよEC2無しのシステム構築の時代がやってきた、と言えるわけです!!ワクワクしますね! blueprintやAPI Gateway等聞きなれない単語が多くて最初は戸惑うかもしれませんがすぐに慣れるのではないでしょうか。尚API Gatewayには独自にSDKを作成する機能もありますので、そちらを使うと複数のLambda Functionを一つのAPI群としてまとめてサービス提供することも可能です! この機能、使い倒してより効率的なシステム構築をしてみましょう!